/*************************************************************************
 *                                                                       *
 * This file is part of the FreeMAPs distribution.  For full copyright   *
 * information, see COPYRIGHT and COPYING.LESSER.                        *
 *                                                                       *
 * Author:           sqbang                                              *
 * Email:            sqbang@ustc.edu                                     *
 * Date:             2014.04.04                                          *
 * Description:      bi-map so that the value can be used as key         *
 *                                                                       *
 *************************************************************************/

namespace FreeMAPs
{

template<typename Key, typename Value>
inline
Bimap<Key, Value>::Bimap ()
{}


template<typename Key, typename Value>
inline void
Bimap<Key, Value>::clear()
{
    d_from_key_to_value.clear();
    d_from_value_to_key.clear();
}


template<typename Key, typename Value>
inline void
Bimap<Key, Value>::insert (
    const Key& k,
    const Value& v)
{
    FREEMAPS_ASSERT (d_from_key_to_value.count (k) == 0);
    FREEMAPS_ASSERT (d_from_value_to_key.count (v) == 0);

    d_from_key_to_value.insert (std::make_pair (k, v));
    d_from_value_to_key.insert (std::make_pair (v, k));
}


template<typename Key, typename Value>
inline bool
Bimap<Key, Value>::is_empty() const
{
    return (d_from_key_to_value.empty() && d_from_value_to_key.empty());
}


template<typename Key, typename Value>
inline std::size_t
Bimap<Key, Value>::size() const
{
    FREEMAPS_ASSERT_EQ (d_from_key_to_value.size(), d_from_value_to_key.size());

    return d_from_key_to_value.size();
}


template<typename Key, typename Value>
inline bool
Bimap<Key, Value>::has_key(
    const Key& k) const
{
    return d_from_key_to_value.count (k) > 0;
}


template<typename Key, typename Value>
inline bool
Bimap<Key, Value>::has_value(
    const Value& v) const
{
    return d_from_value_to_key.count (v) > 0;
}


template<typename Key, typename Value>
inline bool
Bimap<Key, Value>::has_pair(
    const Key& k,
    const Value& v) const
{
    typename std::map<Key, Value>::const_iterator find = d_from_key_to_value.find (k);
    if (find == d_from_key_to_value.end())
    {
        return false;
    }
    else
    {
        return (find->second == v);
    }
}


template<typename Key, typename Value>
inline const Value&
Bimap<Key, Value>::get_value (
    const Key& k) const
{
    typename std::map<Key, Value>::const_iterator find = d_from_key_to_value.find (k);
    FREEMAPS_ASSERT (find != d_from_key_to_value.end());

    return find->second;
}


template<typename Key, typename Value>
inline const Key&
Bimap<Key, Value>::get_key (
    const Value& v) const
{
    typename std::map<Value, Key>::const_iterator find = d_from_value_to_key.find (v);
    FREEMAPS_ASSERT (find != d_from_value_to_key.end());

    return find->second;
}


template<typename Key, typename Value>
inline typename Bimap<Key, Value>::const_iterator
Bimap<Key, Value>::begin() const
{
    return d_from_key_to_value.begin();
}


template<typename Key, typename Value>
inline typename Bimap<Key, Value>::const_iterator
Bimap<Key, Value>::end() const
{
    return d_from_key_to_value.end();
}


template<typename Key, typename Value>
inline typename Bimap<Key, Value>::const_swap_iterator
Bimap<Key, Value>::swap_begin() const
{
    return d_from_value_to_key.begin();
}


template<typename Key, typename Value>
inline typename Bimap<Key, Value>::const_swap_iterator
Bimap<Key, Value>::swap_end() const
{
    return d_from_value_to_key.end();
}


template<typename Key, typename Value>
inline const std::map<Key, Value>&
Bimap<Key, Value>::get_key_map() const
{
    return d_from_key_to_value;
}


template<typename Key, typename Value>
inline const std::map<Value, Key>&
Bimap<Key, Value>::get_value_map() const
{
    return d_from_value_to_key;
}


template<typename Key, typename Value>
inline std::vector<Key>
Bimap<Key, Value>::get_key_vector (
    const bool in_key_order) const
{
    std::vector <Key> keys;
    keys.reserve (d_from_key_to_value.size());

    if (in_key_order)
    {
        for (typename std::map<Key, Value>::const_iterator pos = d_from_key_to_value.begin();
                pos != d_from_key_to_value.end(); ++pos)
        {
            keys.push_back (pos->first);
        }
    }
    else
    {
        for (typename std::map<Value, Key>::const_iterator pos = d_from_value_to_key.begin();
                pos != d_from_value_to_key.end(); ++pos)
        {
            keys.push_back (pos->second);
        }
    }

    return keys;
}


template<typename Key, typename Value>
inline std::vector<Value>
Bimap<Key, Value>::get_value_vector (
    const bool in_key_order) const
{
    std::vector <Value> values;
    values.reserve (d_from_key_to_value.size());

    if (in_key_order)
    {
        for (typename std::map<Key, Value>::const_iterator pos = d_from_key_to_value.begin();
                pos != d_from_key_to_value.end(); ++pos)
        {
            values.push_back (pos->second);
        }
    }
    else
    {
        for (typename std::map<Value, Key>::const_iterator pos = d_from_value_to_key.begin();
                pos != d_from_value_to_key.end(); ++pos)
        {
            values.push_back (pos->first);
        }
    }

    return values;
}


template<typename Key, typename Value>
inline std::set<Key>
Bimap<Key, Value>::get_key_set() const
{
    std::set<Key> keys;
    for (typename std::map<Key, Value>::const_iterator pos = d_from_key_to_value.begin();
            pos != d_from_key_to_value.end(); ++pos)
    {
        keys.insert (pos->first);
    }

    return keys;
}


template<typename Key, typename Value>
inline std::set<Value>
Bimap<Key, Value>::get_value_set() const
{
    std::set<Value> values;
    for (typename std::map<Key, Value>::const_iterator pos = d_from_key_to_value.begin();
            pos != d_from_key_to_value.end(); ++pos)
    {
        values.insert (pos->second);
    }

    return values;
}


template<typename Key, typename Value>
inline void
Bimap<Key, Value>::erase_by_key(
    const Key& key)
{
    typename std::map<Key, Value>::iterator find_key = d_from_key_to_value.find (key);  
     typename std::map<Value, Key>::iterator find_value;
    if (find_key != d_from_key_to_value.end())
   find_value = d_from_value_to_key.find (find_key->second);
    if (find_key != d_from_key_to_value.end())
    {      
        d_from_key_to_value.erase (find_key);        
    }
    if(find_value != d_from_value_to_key.end())
    {
      d_from_value_to_key.erase (find_value);
    }
}


template<typename Key, typename Value>
inline void
Bimap<Key, Value>::erase_by_value(
    const Value& value)
{
    typename std::map<Value, Key>::iterator find_value = d_from_value_to_key.find (value);
    if (find_value != d_from_value_to_key.end())
    {
        d_from_value_to_key.erase (find_value);
        d_from_key_to_value.erase (find_value->second);
    }
}

}
